﻿using ICodeShare.UI.Controls.Core.Common;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;

namespace ICodeShare.UI.Controls.Assists
{
    public static class ToggleButtonAssist
    {
        #region HasOnContent 是否有选中内容

        private static readonly DependencyPropertyKey HasOnContentPropertyKey =
            DependencyProperty.RegisterAttachedReadOnly(
                "HasOnContent", typeof(bool), typeof(ToggleButtonAssist),
                new PropertyMetadata(false));

        public static readonly DependencyProperty HasOnContentProperty = HasOnContentPropertyKey.DependencyProperty;

        private static void SetHasOnContent(DependencyObject element, object value)
        {
            element.SetValue(HasOnContentPropertyKey, value);
        }

        /// <summary>
        /// Framework use only.
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        public static bool GetHasOnContent(DependencyObject element)
        {
            return (bool)element.GetValue(HasOnContentProperty);
        }

        #endregion

        #region OnContent 选中内容

        /// <summary>
        /// Allows on (IsChecked) content to be provided on supporting <see cref="ToggleButton"/> styles.
        /// </summary>
        public static readonly DependencyProperty OnContentProperty = DependencyProperty.RegisterAttached(
            "OnContent", typeof(object), typeof(ToggleButtonAssist), new PropertyMetadata(default(object), OnContentPropertyChangedCallback));

        private static void OnContentPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
        {
            SetHasOnContent(dependencyObject, dependencyPropertyChangedEventArgs.NewValue != null);
        }

        /// <summary>
        /// Allows on (IsChecked) content to be provided on supporting <see cref="ToggleButton"/> styles.
        /// </summary>
        /// <param name="element"></param>
        /// <param name="value"></param>
        public static void SetOnContent(DependencyObject element, object value)
        {
            element.SetValue(OnContentProperty, value);
        }

        /// <summary>
        /// Allows on (IsChecked) content to be provided on supporting <see cref="ToggleButton"/> styles.
        /// </summary>
        public static object GetOnContent(DependencyObject element)
        {
            return (object)element.GetValue(OnContentProperty);
        }

        #endregion

        #region OnContentTemplate 选中内容样式

        /// <summary>
        /// Allows an on (IsChecked) template to be provided on supporting <see cref="ToggleButton"/> styles.
        /// </summary>
        public static readonly DependencyProperty OnContentTemplateProperty = DependencyProperty.RegisterAttached(
            "OnContentTemplate", typeof(DataTemplate), typeof(ToggleButtonAssist), new PropertyMetadata(default(DataTemplate)));

        /// <summary>
        /// Allows an on (IsChecked) template to be provided on supporting <see cref="ToggleButton"/> styles.
        /// </summary>
        public static void SetOnContentTemplate(DependencyObject element, DataTemplate value)
        {
            element.SetValue(OnContentTemplateProperty, value);
        }

        /// <summary>
        /// Allows an on (IsChecked) template to be provided on supporting <see cref="ToggleButton"/> styles.
        /// </summary>
        public static DataTemplate GetOnContentTemplate(DependencyObject element)
        {
            return (DataTemplate)element.GetValue(OnContentTemplateProperty);
        }

        #endregion

        #region HasOnIcon 是否有选中图标
        /// <summary>
        /// Framework use only.
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        public static bool GetHasOnIcon(DependencyObject element)
        {
            return (bool)element.GetValue(HasOnIconProperty);
        }

        private static void SetHasOnIcon(DependencyObject element, object value)
        {
            element.SetValue(HasOnIconPropertyKey, value);
        }

        private static readonly DependencyPropertyKey HasOnIconPropertyKey =
            DependencyProperty.RegisterAttachedReadOnly(
                "HasOnIcon",
                typeof(bool),
                typeof(ToggleButtonAssist),
                new PropertyMetadata(false));

        public static readonly DependencyProperty HasOnIconProperty = HasOnIconPropertyKey.DependencyProperty;




        #endregion

        #region OnIcon 选中图标内容

        /// <summary>
        /// Allows on (IsChecked) content to be provided on supporting <see cref="ToggleButton"/> styles.
        /// </summary>
        /// <param name="element"></param>
        /// <param name="value"></param>
        public static void SetOnIcon(DependencyObject element, object value)
        {
            element.SetValue(OnIconProperty, value);
        }

        /// <summary>
        /// Allows on (IsChecked) content to be provided on supporting <see cref="ToggleButton"/> styles.
        /// </summary>
        public static object GetOnIcon(DependencyObject element)
        {
            return (object)element.GetValue(OnIconProperty);
        }

        /// <summary>
        /// Allows on (IsChecked) content to be provided on supporting <see cref="ToggleButton"/> styles.
        /// </summary>
        public static readonly DependencyProperty OnIconProperty = DependencyProperty.RegisterAttached(
            "OnIcon",
            typeof(object),
            typeof(ToggleButtonAssist),
            new PropertyMetadata(default(object),
                OnIconPropertyChangedCallback));

        private static void OnIconPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
        {
            SetHasOnIcon(dependencyObject, dependencyPropertyChangedEventArgs.NewValue != null);
        }

        #endregion

        #region OnIconTemplate 选中图标内容样式

        /// <summary>
        /// Allows an on (IsChecked) template to be provided on supporting <see cref="ToggleButton"/> styles.
        /// </summary>
        public static readonly DependencyProperty OnIconTemplateProperty = DependencyProperty.RegisterAttached(
            "OnIconTemplate",
            typeof(DataTemplate), 
            typeof(ToggleButtonAssist),
            new PropertyMetadata(default(DataTemplate)));

        /// <summary>
        /// Allows an on (IsChecked) template to be provided on supporting <see cref="ToggleButton"/> styles.
        /// </summary>
        public static void SetOnIconTemplate(DependencyObject element, DataTemplate value)
        {
            element.SetValue(OnIconTemplateProperty, value);
        }

        /// <summary>
        /// Allows an on (IsChecked) template to be provided on supporting <see cref="ToggleButton"/> styles.
        /// </summary>
        public static DataTemplate GetOnIconTemplate(DependencyObject element)
        {
            return (DataTemplate)element.GetValue(OnIconTemplateProperty);
        }

        #endregion

        #region OnIconBrush 选中图标颜色

        /// <summary>
        ///
        /// </summary>
        [AttachedPropertyBrowsableForType(typeof(ButtonBase))]
        [AttachedPropertyBrowsableForType(typeof(ToggleButton))]
        [AttachedPropertyBrowsableForType(typeof(CheckBox))]
        [AttachedPropertyBrowsableForType(typeof(RadioButton))]
        [AttachedPropertyBrowsableForType(typeof(FastIcon))]
        [AttachedPropertyBrowsableForType(typeof(PackIcon))]
        [AttachedPropertyBrowsableForType(typeof(StyleIcon))]
        public static Brush GetOnIconBrush(DependencyObject element)
        {
            return (Brush)element.GetValue(OnIconBrushProperty);
        }

        /// <summary>
        ///
        /// </summary>
        public static void SetOnIconBrush(DependencyObject element, Brush value)
        {
            element.SetValue(OnIconBrushProperty, value);
        }

        // Using a DependencyProperty as the backing store for OnIconBrush.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty OnIconBrushProperty =
            DependencyProperty.RegisterAttached(
            "OnIconBrush",
            typeof(Brush),
            typeof(ToggleButtonAssist),
            new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits));

        #endregion IconBrush 图标颜色

        #region Direction 箭头方向

        /// <summary>
        /// Gets the brush used to draw the mouse pressed border.
        /// </summary>
        [AttachedPropertyBrowsableForType(typeof(ToggleButton))]
        public static Direction GetDirection(DependencyObject element)
        {
            return (Direction)element.GetValue(DirectionProperty);
        }

        /// <summary>
        /// Sets the brush used to draw the mouse pressed border.
        /// </summary>
        public static void SetDirection(DependencyObject element, Direction value)
        {
            element.SetValue(DirectionProperty, value);
        }

        /// <summary>
        /// DependencyProperty for <see cref="Direction" /> property.
        /// </summary>
        public static readonly DependencyProperty DirectionProperty = DependencyProperty.RegisterAttached(
            "Direction",
            typeof(Direction),
            typeof(ToggleButtonAssist),
            new FrameworkPropertyMetadata(Direction.Down,
                FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits));

        #endregion Direction 箭头方向

        #region ICommand 命令

        #region CanCommandBinding 是否支持命令绑定

        /// <summary>
        /// Get where show the shadow for waiting data
        /// </summary>
        [AttachedPropertyBrowsableForType(typeof(ToggleButton))]
        [AttachedPropertyBrowsableForType(typeof(CheckBox))]
        [AttachedPropertyBrowsableForType(typeof(RadioButton))]
        public static bool GetCanCommandBinding(DependencyObject element)
        {
            return (bool)element.GetValue(CanCommandBindingProperty);
        }

        /// <summary>
        /// Set where show the shadow for waiting data
        /// </summary>
        public static void SetCanCommandBinding(DependencyObject element, bool value)
        {
            element.SetValue(CanCommandBindingProperty, value);
        }

        /// <summary>
        /// DependencyProperty for <see cref="CanCommandBinding" /> property.
        /// </summary>
        public static readonly DependencyProperty CanCommandBindingProperty = DependencyProperty.RegisterAttached(
            "CanCommandBinding",
            typeof(bool),
            typeof(ToggleButtonAssist),
            new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits, OnCanCommandBindingChanged));

        static void OnCanCommandBindingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
             var toggle = d as ToggleButton;
             if (toggle != null)
             {
                 if ((bool)e.NewValue)
                 {
                     
                     toggle.Checked += ToggleButtonChecked;
                     toggle.Dispatcher.BeginInvoke((Action)(() =>
                      ToggleButtonChecked(toggle, new RoutedEventArgs(ToggleButton.CheckedEvent, toggle))));

                     toggle.Unchecked += ToggleButtonUnchecked;
                     toggle.Dispatcher.BeginInvoke((Action)(() =>
                       ToggleButtonUnchecked(toggle, new RoutedEventArgs(ToggleButton.UncheckedEvent, toggle))));
                 }
                 else
                 {
                     toggle.Checked -= ToggleButtonChecked;
                     toggle.Unchecked -= ToggleButtonUnchecked;
                 }
             }

        }

        #endregion CanCommandBinding 是否可清空

        #region CheckChangedCommand 选中状态改变命令
        [AttachedPropertyBrowsableForType(typeof(ToggleButton))]
        [AttachedPropertyBrowsableForType(typeof(CheckBox))]
        [AttachedPropertyBrowsableForType(typeof(RadioButton))]
        public static ICommand GetCheckChangedCommand(DependencyObject d)
        {
            return (ICommand)d.GetValue(CheckChangedCommandProperty);
        }

        public static void SetCheckChangedCommand(DependencyObject obj, ICommand value)
        {
            obj.SetValue(CheckChangedCommandProperty, value);
        }

        public static readonly DependencyProperty CheckChangedCommandProperty = DependencyProperty.RegisterAttached(
            "CheckChangedCommand",
            typeof(ICommand),
            typeof(ToggleButtonAssist),
            new FrameworkPropertyMetadata(null));
        #endregion

        #region CheckChangedCommandParameter 选中状态改变命令参数
        [AttachedPropertyBrowsableForType(typeof(ToggleButton))]
        [AttachedPropertyBrowsableForType(typeof(CheckBox))]
        [AttachedPropertyBrowsableForType(typeof(RadioButton))]
        public static object GetCheckChangedCommandParameter(DependencyObject d)
        {
            return (object)d.GetValue(CheckChangedCommandParameterProperty);
        }

        public static void SetCheckChangedCommandParameter(DependencyObject obj, object value)
        {
            obj.SetValue(CheckChangedCommandParameterProperty, value);
        }

        public static readonly DependencyProperty CheckChangedCommandParameterProperty = DependencyProperty.RegisterAttached(
            "CheckChangedCommandParameter",
            typeof(object),
            typeof(ToggleButtonAssist),
            new FrameworkPropertyMetadata(null));


        #endregion

        #region CheckedCommand 选中命令
        [AttachedPropertyBrowsableForType(typeof(ToggleButton))]
        [AttachedPropertyBrowsableForType(typeof(CheckBox))]
        [AttachedPropertyBrowsableForType(typeof(RadioButton))]
        public static ICommand GetCheckedCommand(DependencyObject d)
        {
            return (ICommand)d.GetValue(CheckedCommandProperty);
        }

        public static void SetCheckedCommand(DependencyObject obj, ICommand value)
        {
            obj.SetValue(CheckedCommandProperty, value);
        }

        public static readonly DependencyProperty CheckedCommandProperty = DependencyProperty.RegisterAttached(
            "CheckedCommand",
            typeof(ICommand),
            typeof(ToggleButtonAssist),
            new FrameworkPropertyMetadata(null));
        #endregion

        #region CheckedCommandParameter 选中命令参数
        [AttachedPropertyBrowsableForType(typeof(ToggleButton))]
        [AttachedPropertyBrowsableForType(typeof(CheckBox))]
        [AttachedPropertyBrowsableForType(typeof(RadioButton))]
        public static object GetCheckedCommandParameter(DependencyObject d)
        {
            return (object)d.GetValue(CheckedCommandParameterProperty);
        }

        public static void SetCheckedCommandParameter(DependencyObject obj, object value)
        {
            obj.SetValue(CheckedCommandParameterProperty, value);
        }

        public static readonly DependencyProperty CheckedCommandParameterProperty = DependencyProperty.RegisterAttached(
            "CheckedCommandParameter",
            typeof(object),
            typeof(ToggleButtonAssist),
            new FrameworkPropertyMetadata(null));


        #endregion

        #region UncheckedCommand 未选中命令
        [AttachedPropertyBrowsableForType(typeof(ToggleButton))]
        [AttachedPropertyBrowsableForType(typeof(CheckBox))]
        [AttachedPropertyBrowsableForType(typeof(RadioButton))]
        public static ICommand GetUncheckedCommand(DependencyObject d)
        {
            return (ICommand)d.GetValue(UncheckedCommandProperty);
        }

        public static void SetUncheckedCommand(DependencyObject obj, ICommand value)
        {
            obj.SetValue(UncheckedCommandProperty, value);
        }

        public static readonly DependencyProperty UncheckedCommandProperty = DependencyProperty.RegisterAttached(
            "UncheckedCommand",
            typeof(ICommand),
            typeof(ToggleButtonAssist),
            new FrameworkPropertyMetadata(null));
        #endregion

        #region UncheckedCommandParameter 未选中命令参数
        [AttachedPropertyBrowsableForType(typeof(ToggleButton))]
        [AttachedPropertyBrowsableForType(typeof(CheckBox))]
        [AttachedPropertyBrowsableForType(typeof(RadioButton))]
        public static object GetUncheckedCommandParameter(DependencyObject d)
        {
            return (object)d.GetValue(UncheckedCommandParameterProperty);
        }

        public static void SetUncheckedCommandParameter(DependencyObject obj, object value)
        {
            obj.SetValue(UncheckedCommandParameterProperty, value);
        }

        public static readonly DependencyProperty UncheckedCommandParameterProperty = DependencyProperty.RegisterAttached(
            "UncheckedCommandParameter",
            typeof(object),
            typeof(ToggleButtonAssist),
            new FrameworkPropertyMetadata(null));


        #endregion

        #endregion

        #region Methods
        /// <summary>
        /// 选中事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        static void ToggleButtonChecked(object sender, RoutedEventArgs e)
        {
            var toggle = sender as ToggleButton;
            if (toggle == null)
                return;

            var checkChangedCommand = GetCheckChangedCommand(toggle);
            var checkChangedCommandParameter = GetCheckChangedCommandParameter(toggle) ?? toggle;
            if (checkChangedCommand != null && checkChangedCommand.CanExecute(checkChangedCommandParameter))
            {
                checkChangedCommand.Execute(checkChangedCommandParameter);
            }

            var checkedCommand = GetCheckedCommand(toggle);
            var checkedCommandParameter = GetCheckedCommandParameter(toggle) ?? toggle;
            if (checkedCommand != null && checkedCommand.CanExecute(checkedCommandParameter))
            {
                checkedCommand.Execute(checkedCommandParameter);
            }
        }

        /// <summary>
        /// 未选中事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        static void ToggleButtonUnchecked(object sender, RoutedEventArgs e)
        {
            var toggle = sender as ToggleButton;
            if (toggle == null)
                return;

            var checkChangedCommand = GetCheckChangedCommand(toggle);
            var checkChangedCommandParameter = GetCheckChangedCommandParameter(toggle) ?? toggle;
            if (checkChangedCommand != null && checkChangedCommand.CanExecute(checkChangedCommandParameter))
            {
                checkChangedCommand.Execute(checkChangedCommandParameter);
            }

            var uncheckedCommand = GetUncheckedCommand(toggle);
            var uncheckedCommandParameter = GetUncheckedCommandParameter(toggle) ?? toggle;
            if (uncheckedCommand != null && uncheckedCommand.CanExecute(uncheckedCommandParameter))
            {
                uncheckedCommand.Execute(uncheckedCommandParameter);
            }
        }
        #endregion
    }
}